open Base

module type S = sig
  type t
  type comparator_witness
  val comparator : (t, comparator_witness) Comparator.comparator
  val to_string : t -> string
  val equal : t -> t -> bool
  val compare : t -> t -> int
  val create : unit -> t
  module Private : sig val ahead : int -> t end

  type +'a map = (t, 'a, comparator_witness) Map.t
  type set = (t, comparator_witness) Set.t
  val empty_map : 'a map
  val empty_set : set
end

module Make(B : sig val name : string end) : S = struct
  include (Int : Comparable.S
           with type t = int
            and type comparator_witness = Int.comparator_witness)
  let to_string n = Printf.sprintf "<%s:%d>" B.name n
  let next = ref 0
  let create () = Int.incr next ; !next
  module Private = struct let ahead n = n + !next end

  type +'a map = (t, 'a, comparator_witness) Map.t
  type set = (t, comparator_witness) Set.t
  let empty_map = Map.empty (module Int)
  let empty_set = Set.empty (module Int)
end

let make name : (module S) =
  (module Make(struct let name = name end))

module Ids = struct
  module Sink_id = (val make "sink")
  module Src_id = (val make "src")
  module Var_id = (val make "var")
end
